package goboot

import (
	"encoding/json"
	"log"
	"net/http"
	"os"
	"reflect"
	"strconv"
	"strings"
)

var webDocMethodList []*WebDocMethod
var webDocMethodUrlMap map[string]map[string]*WebDocMethod //url -> methodName -> WebDocMethod

// 文档对象
type WebDocMethod struct {
	UrlPath               string              `json:"urlPath"`               //url路径
	WebMethod             string              `json:"webMethod"`             //http方法
	Name                  string              `json:"name"`                  //名称
	MethodName            string              `json:"methodName"`            //方法名称
	StructName            string              `json:"structName"`            //结构体名称
	StructFullPackageName string              `json:"structFullPackageName"` //带module的包名
	PackageName           string              `json:"packageName"`           //包名称
	ParamList             []WebDocMethodParam `json:"paramList"`             //参数列表
	PathParams            []string            `json:"pathParams"`            //路径参数列表
	methodValue           *reflect.Value

	CommentAspectList []string `json:"aspectList"`       //切面列表
	CommentName       string   `json:"commentName"`      //注释名称
	CommentDesc       string   `json:"commentDesc"`      //注释描述
	CommentGroupName  string   `json:"commentGroupName"` //注释分类
	CommentTime       int64    `json:"commentTime"`      //注释时间
	CommentBackStr    string   `json:"commentBackStr"`   //注释返回值
}

type WebDocMethodParam struct {
	Name     string `json:"name"`     //参数名称
	TypeName string `json:"typeName"` //参数类型名称
	DescStr  string `json:"descStr"`  //参数描述
	LikeStr  string `json:"likeStr"`  //参数示例
	DefStr   string `json:"defStr"`   //参数默认值
}

func bindUrlMethod() {

	webDocMethodUrlMap = make(map[string]map[string]*WebDocMethod)
	for _, controller := range restControllers {

		controllerRefType := reflect.TypeOf(controller)
		controllerRefValue := reflect.ValueOf(controller)

		baseUrl := controller.GoBootBaseUrl()

		for i := 0; i < controllerRefType.NumMethod(); i++ {

			method := controllerRefType.Method(i)
			methodVa := controllerRefValue.Method(i)
			if method.Name == "GoBootBaseUrl" {
				continue
			}

			pathParams := strings.Split(method.Name, "__")
			name := pathParams[0]

			curMethod := ""
			curName := name

			if strings.HasPrefix(name, "ALL_") {
				curMethod = ""
				curName = name[strings.Index(name, "ALL_")+4:]
			} else if strings.HasPrefix(name, http.MethodGet+"_") {
				curMethod = http.MethodGet
				curName = name[strings.Index(name, http.MethodGet+"_")+4:]
			} else if strings.HasPrefix(name, http.MethodPost+"_") {
				curMethod = http.MethodPost
				curName = name[strings.Index(name, http.MethodPost+"_")+5:]
			} else if strings.HasPrefix(name, http.MethodPut+"_") {
				curMethod = http.MethodPut
				curName = name[strings.Index(name, http.MethodPut+"_")+4:]
			} else if strings.HasPrefix(name, http.MethodDelete+"_") {
				curMethod = http.MethodDelete
				curName = name[strings.Index(name, http.MethodDelete+"_")+7:]
			} else {

				curMethod = ""
				curName = name
			}

			packageName := controllerPackageNameMap[controller]
			controllerStructName := controllerStructNameMap[controller]
			var webDocMethod *WebDocMethod

			for i := 0; i < len(webDocMethodList); i++ {
				if webDocMethodList[i].StructFullPackageName == packageName && webDocMethodList[i].StructName == controllerStructName && webDocMethodList[i].MethodName == method.Name {
					webDocMethod = webDocMethodList[i]
					break
				}
			}

			//填充具体的信息

			if baseUrl == "/" {
				webDocMethod.UrlPath = "/" + curName
			} else {
				webDocMethod.UrlPath = baseUrl + "/" + curName
			}

			webDocMethod.WebMethod = curMethod
			webDocMethod.methodValue = &methodVa

			for i, s := range pathParams {
				if i == 0 {
					continue
				}
				webDocMethod.PathParams = append(webDocMethod.PathParams, s)
			}

			if _, ok := webDocMethodUrlMap[webDocMethod.UrlPath]; !ok {
				webDocMethodUrlMap[webDocMethod.UrlPath] = make(map[string]*WebDocMethod)
			}
			webDocMethodUrlMap[webDocMethod.UrlPath][webDocMethod.WebMethod] = webDocMethod

		}

	}

}

func initWebDocMethods(fromAutoCode bool) {

	if !fromAutoCode {

		//已只读方式打开文件

		file, err := os.Open(serverConfig.GobootWebUrlJson)
		if err != nil {
			log.Fatalf("打开JSON文件错误: %v", err)
		}
		defer file.Close()

		decoder := json.NewDecoder(file)
		err = decoder.Decode(&webDocMethodList)
		if err != nil {
			log.Fatalf("解析JSON文件错误: %v", err)
		}

		return
	}

	for _, method := range oriMethodList {

		if method.Name == "GoBootBaseUrl" {
			continue
		}

		//判断是不是接口
		webUrlIs := false
		for _, me := range oriMethodList {
			if me.BelongStructName == method.BelongStructName && me.Name == "GoBootBaseUrl" {
				webUrlIs = true
				break
			}
		}

		if !webUrlIs {
			continue
		}

		paramList := []WebDocMethodParam{}
		for _, param := range method.ParamList {
			paramList = append(paramList, WebDocMethodParam{
				Name:     param.Name,
				TypeName: param.TypeName,
			})
		}
		aaa := &WebDocMethod{
			MethodName:            method.Name,
			StructName:            method.BelongStructName,
			StructFullPackageName: method.BelongStructFullPackageName,
			PackageName:           method.PackageName,
			ParamList:             paramList,
		}
		delCommentStr(method.CommentStr, aaa)
		webDocMethodList = append(webDocMethodList, aaa)

	}

}

func delCommentStr(commentStr string, webDocMethod *WebDocMethod) {

	coms := strings.Split(commentStr, "\n")

	for _, com := range coms {

		defaultStr := false

		if len(com) >= 6 {
			if com[0:6] == "@time " {
				defaultStr = true
				// 将字符串转换为 uint64 类型
				var err error
				webDocMethod.CommentTime, err = strconv.ParseInt(strings.TrimSpace(com[6:]), 10, 64)
				if err != nil {
					log.Printf("将 @time 后的字符串转换为 int64 类型时出错: %v", err)
				}
			}
			if com[0:6] == "@name " {
				defaultStr = true
				webDocMethod.CommentName = strings.TrimSpace(com[6:])
				webDocMethod.Name = webDocMethod.CommentName
			}
		}
		if len(com) >= 7 {

			if com[0:7] == "@param " {
				defaultStr = true

				exHeadParam := strings.TrimSpace(com[7:])
				paramName := exHeadParam[0:strings.Index(exHeadParam, " ")]
				//fmt.Println(paramName)

				for i := range webDocMethod.ParamList {
					if webDocMethod.ParamList[i].Name == paramName {
						webDocMethod.ParamList[i].DescStr = strings.TrimSpace(exHeadParam[strings.Index(exHeadParam, " ")+1:])

						sp := strings.Split(webDocMethod.ParamList[i].DescStr, " -l- ")

						if len(sp) > 1 {
							webDocMethod.ParamList[i].DescStr = sp[0]
							webDocMethod.ParamList[i].LikeStr = sp[1]
						}
						if strings.Contains(webDocMethod.ParamList[i].LikeStr, " -d- ") {

							sp := strings.Split(webDocMethod.ParamList[i].LikeStr, " -d- ")

							if len(sp) > 1 {
								webDocMethod.ParamList[i].LikeStr = sp[0]
								webDocMethod.ParamList[i].DefStr = sp[1]
							}
						} else if strings.Contains(webDocMethod.ParamList[i].DescStr, " -d- ") {

							sp := strings.Split(webDocMethod.ParamList[i].DescStr, " -d- ")

							if len(sp) > 1 {
								webDocMethod.ParamList[i].DescStr = sp[0]
								webDocMethod.ParamList[i].DefStr = sp[1]
							}
						}

					}
				}
			}

			if com[0:7] == "@back {" || com[0:7] == "@back [" {
				defaultStr = true

				webDocMethod.CommentBackStr = strings.TrimSpace(com[7 : len(com)-1])

				curPackageName := webDocMethod.PackageName
				curStructName := ""

				if strings.Contains(webDocMethod.CommentBackStr, ".") {
					curPackageName = strings.Split(webDocMethod.CommentBackStr, ".")[0]
					curStructName = strings.Split(webDocMethod.CommentBackStr, ".")[1]

				} else {
					curStructName = webDocMethod.CommentBackStr
				}

				for _, oriStruct := range oriStructList {

					if oriStruct.PackageName == curPackageName && oriStruct.StructName == curStructName {
						webDocMethod.CommentBackStr = ""
						for _, fieldInfo := range oriStruct.FiledList {

							nameStr := ""
							if fieldInfo.TagStr != "" {
								nameStr = fieldInfo.TagStr[(strings.Index(fieldInfo.TagStr, "json:") + 6):]
								nameStr = nameStr[0:strings.Index(nameStr, `"`)]
								webDocMethod.CommentBackStr += "\t" + nameStr + "  " + strings.ReplaceAll(fieldInfo.TypeName, "*", "") + " " + fieldInfo.CommentStr
							}

						}
						break
					}

				}

				if com[0:7] == "@back [" {
					webDocMethod.CommentBackStr = "[\n" + webDocMethod.CommentBackStr + "]"
				} else {

					webDocMethod.CommentBackStr = "{\n" + webDocMethod.CommentBackStr + "}"
				}

			}
			if com[0:6] == "@badd " {
				defaultStr = true

				webDocMethod.CommentBackStr = webDocMethod.CommentBackStr[:len(webDocMethod.CommentBackStr)-1]
				webDocMethod.CommentBackStr += "\t" + strings.TrimSpace(com[6:]) + "\n}"

			}

		}
		if len(com) >= 8 {
			if com[0:8] == "@aspect " {
				defaultStr = true
				webDocMethod.CommentAspectList = append(webDocMethod.CommentAspectList, strings.TrimSpace(com[8:]))
			}
		}
		if len(com) >= 11 {
			if com[0:11] == "@groupName " {
				defaultStr = true
				webDocMethod.CommentGroupName = strings.TrimSpace(com[11:])
			}
		}

		/*
			if len(com) >= 7 {
				if com[0:7] == "@cache " {
					defaultStr = true
					// 将字符串转换为 uint64 类型
					var err error
					sysApi.CacheTime, err = strconv.ParseInt(strings.TrimSpace(com[6:]), 10, 64)
					if err != nil {
						log.Printf("将 @cache 后的字符串转换为 uint64 类型时出错: %v", err)
					}
				}
			} */

		/* 		if len(com) > 6 {
			if com[0:7] == "@param " {
				defaultStr = true

				exHeadParam := strings.TrimSpace(com[7:])

				paramName := exHeadParam[0:strings.Index(exHeadParam, " ")]

				for i := range sysApi.Params {
					if sysApi.Params[i].Name == paramName {
						sysApi.Params[i].DescStr = strings.TrimSpace(exHeadParam[strings.Index(exHeadParam, " ")+1:])

						sp := strings.Split(sysApi.Params[i].DescStr, " -l- ")

						if len(sp) > 1 {
							sysApi.Params[i].DescStr = sp[0]
							sysApi.Params[i].LikeStr = sp[1]
						}

					}
				}

				//fmt.Println(paramName)

			}
		} */
		/*
			if len(com) > 6 {

				if com[0:7] == "@back {" || com[0:7] == "@back [" {
					defaultStr = true
					spit := strings.Split(strings.TrimSpace(com[7:len(com)-1]), ".")

					for _, importStr := range importStrs {

						importStr = importStr[1 : len(importStr)-1]

						if strings.HasSuffix(importStr, spit[0]) {
							structInfo := StructInfoMap[importStr+"/"+spit[1]]

							for _, fieldInfo := range structInfo.FuncFieldInfos {

								apiBack := ""
								if strings.HasSuffix(fieldInfo.Type, "}") && fieldInfo.Name != "" {
									apiBack += fieldInfo.Type[strings.LastIndex(fieldInfo.Type, " ")+1 : len(fieldInfo.Type)-1]

								} else {
									if fieldInfo.Name != "" {

										apiBack += fieldInfo.Type
									}
								}

								if fieldInfo.Name != "" {
									apiBack += " " + toLow(fieldInfo.Name) + " " + fieldInfo.ComStr
								}

								if apiBack != "" {
									sysApi.BackStrs = append(sysApi.BackStrs, apiBack)
								}
							}

						}

					}

				}
			} */
		/*
			if len(com) >= 6 {
				if com[0:6] == "@badd " {
					defaultStr = true
					sysApi.BackStrs = append(sysApi.BackStrs, strings.TrimSpace(com[6:]))
				}
			}
		*/
		if "\n" == com {
			defaultStr = true

		}
		if "" == com {
			defaultStr = true

		}

		if !defaultStr {
			webDocMethod.CommentDesc = webDocMethod.CommentDesc + com + "\n"
		}

	}

	if len(webDocMethod.CommentDesc) > 2 && webDocMethod.CommentDesc[len(webDocMethod.CommentDesc)-1:] == "\n" {
		webDocMethod.CommentDesc = webDocMethod.CommentDesc[0 : len(webDocMethod.CommentDesc)-1]
	}

}
